<script setup lang="ts">
import {computed, type ComputedRef, onMounted, ref, useAttrs} from "vue";
import type TableColumn from './type/TableColumn.ts'
import {copyToClipboard} from "@/components/strs.ts";

const $emit = defineEmits(["switch-change", "radio-change"])
const $prop = defineProps<{
  columns: TableColumn[]
  //表体高度
  height?: string
  data: Record<string, any>[]
  loading?: boolean
  tree?: boolean
}>()

const attrs = useAttrs()
//阻止默认透传到根节点
defineOptions({
  inheritAttrs: false
})

const height = $prop.height ?? "calc(100% - 40px)"

//记录每个节点是否展开，用主键作为 key
const expandedMap = ref<Record<string, boolean>>({})

function val(col: TableColumn, row: Record<string, any>): ComputedRef {
  return computed(() => {
    return col.callback ? col.callback(row) : row[col.key]
  })
}

/**
 * 动态生成grid的样式
 */
const gridStyle = computed(() => {
  let styleStr = $prop.columns
      .map(col => col.width ? `${col.width}px` : 'minmax(120px, 1fr)')
      .join(' ');

  // 如果是树形表格，在最前面添加一个固定宽度的展开列
  if ($prop.tree) {
    styleStr = '50px ' + styleStr;
  }

  return {
    display: 'grid',
    //自动计算每一列的宽度，如果有width属性，就使用width，没有就默认均分一行
    gridTemplateColumns: styleStr
  }
})

// —— 新增：固定列偏移计算 ——

// 获取列宽（用于计算 sticky 偏移）。未设置则按 120 兜底，保持你现有“minmax(120px, 1fr)”的语义一致。
function getColWidth(col: TableColumn): number {
  return typeof col.width === 'number' ? col.width : 120
}

// 左侧固定列的累计偏移
const leftOffsets = computed(() => {
  const offsets: Record<string, number> = {}
  let acc = 0
  for (const col of $prop.columns) {
    if (col.fixed === 'left') {
      offsets[col.key] = acc
      acc += getColWidth(col)
    }
  }
  return offsets
})

// 右侧固定列的累计偏移（从右往左）
const rightOffsets = computed(() => {
  const offsets: Record<string, number> = {}
  let acc = 0
  for (let i = $prop.columns.length - 1; i >= 0; i--) {
    const col = $prop.columns[i]
    if (col.fixed === 'right') {
      offsets[col.key] = acc
      acc += getColWidth(col)
    }
  }
  return offsets
})

// 为固定列生成 sticky 样式；未固定则返回空对象，不影响现有逻辑
function stickyStyle(col: TableColumn): Record<string, any> {
  if (col.fixed === 'left') {
    return {
      position: 'sticky',
      left: `${leftOffsets.value[col.key] ?? 0}px`,
      zIndex: 6,             // 高于普通单元格，避免被覆盖
      background: '#fff'     // 防止内容透出
    }
  } else if (col.fixed === 'right') {
    return {
      position: 'sticky',
      right: `${rightOffsets.value[col.key] ?? 0}px`,
      zIndex: 6,
      background: '#fff'
    }
  }
  return {}
}

//递归渲染行，添加缩进和展开按钮
function renderRows(rows: Record<string, any>[], level = 0): any[] {
  const rendered: any[] = []

  for (const row of rows) {
    const id = row.id ?? Math.random().toString(36).slice(2) // 确保有唯一 key
    const isExpanded = expandedMap.value[id] ?? false
    const hasChildren = row.children && row.children.length > 0

    // 主行
    rendered.push({
      row,
      level,
      id,
      hasChildren,
      isExpanded,
    })

    // 如果展开，递归 children
    if (hasChildren && isExpanded) {
      rendered.push(...renderRows(row.children, level + 1))
    }
  }

  return rendered
}

const renderedRows = computed(() => {
  return $prop.tree ? renderRows($prop.data) : $prop.data.map((row, i) => ({
    row,
    level: 0,
    id: row.id ?? i,
    hasChildren: false,
    isExpanded: false
  }))
})

const bodyRef = ref<HTMLElement | null>(null)
const isScrolled = ref(false)

//表格体滚动时的回调函数
function onBodyScroll() {
  if (bodyRef.value) {
    isScrolled.value = bodyRef.value.scrollTop > 0
  }
}

onMounted(() => {
  if (!Array.isArray($prop.data)) {
    console.warn('[t-table] props.data 必须是数组类型，例如: :data="[item]"')
  }
})
</script>

<template>
  <div class="table-container" role="table">
    <div class="table-header">
      <slot name="header"></slot>
    </div>
    <div class="table-body">
      <!-- 表头 -->
      <div class="header" :class="{ 'is-scrolled': isScrolled }" :style="gridStyle">
        <!-- 树形表格的展开列表头 -->
        <div v-if="$prop.tree" class="tree-header-col">
          <!-- 可以放置全部展开/收起的按钮 -->
        </div>
        <div
            v-for="col in columns"
            :key="col.key"
            :style="{
            ...stickyStyle(col),
            justifyContent: col.align === 'left' ? 'flex-start' : col.align === 'right' ? 'flex-end' : 'center'
          }"
        >
          {{ col.title }}
        </div>
      </div>

      <!-- 表体 -->
      <div class="body" ref="bodyRef" @scroll="onBodyScroll">
        <TransitionGroup name="tree-row-fade" tag="div">
          <div
              class="row"
              v-for="({ row, level, id, hasChildren, isExpanded }, rowIndex) in renderedRows"
              :key="id"
              :style="gridStyle"
              :class="{
              'tree-row': $prop.tree && level > 0,
              [`tree-level-${level}`]: $prop.tree,
              'has-children': hasChildren && $prop.tree
            }"
              @click.stop>

            <!-- 如果是树形表格，就将第一列设为展开/收起列 -->
            <div v-if="$prop.tree" class="col">
              <!-- 存在下级数据，就展示箭头图标 -->
              <span v-if="hasChildren"
                    @click.stop="expandedMap[id] = !isExpanded"
                    class="tree-expand-btn"
                    :class="{ 'expanded': isExpanded }">
                <component is="right" class="expand-icon"/>
              </span>
              <!-- 不存在下级数据 -->
              <span v-else-if="level > 0" class="tree-leaf-icon">
              </span>
            </div>

            <!-- 遍历所有列 -->
            <div class="col"
                 v-for="(col, colIndex) in columns"
                 :key="col.key"
                 :style="{
                   ...stickyStyle(col),                                   // —— 新增：仅对固定列生效
                   justifyContent: col.align === 'left' ? 'flex-start' : col.align === 'right' ? 'flex-end' : 'center',
                   paddingLeft: $prop.tree && colIndex === 0 ? `${level * 15}px` : '0px'
                 }"
                 @dblclick="copyToClipboard(row[col.key])"
            >
              <!-- 下标 -->
              <div v-if="col.type === 'index'">
                {{ rowIndex + 1 }}
              </div>

              <!-- 单选 -->
              <div v-else-if="col.type === 'radio'">
                <input
                    type="radio"
                    :name="'t-table-radio'"
                    :checked="val(col, row).value"
                    @change="(e) => $emit('radio-change', row)"/>
              </div>

              <!-- 插槽 -->
              <div v-else-if="col.type === 'slot' " class="slot-wrapper">
                <slot :name="col.key" :row="row"/>
              </div>

              <!-- 开关 -->
              <template v-else-if="col.type === 'switch'">
                <t-switch v-model="row[col.key]" v-bind="col.attr"/>
              </template>

              <!-- 文本 -->
              <template v-else-if="col.type === 'string'">
                <span @click="() => col.click?.(row)" class="cell-text">
                  <t-tooltip :msg="val(col, row).value">
                    {{ val(col, row).value }}
                  </t-tooltip>
                </span>
              </template>

              <!-- 标签 -->
              <template v-else-if="col.type?.startsWith('tag')">
                <t-tag v-bind="col.attr" :code="val(col, row).value" :label="val(col, row).value"/>
              </template>

              <!-- 日期 -->
              <template v-else-if="col.type === 'date'">
                <span @click="() => col.click?.(row)" class="cell-text">
                  {{ val(col, row).value }}
                </span>
              </template>

              <!-- 数字 -->
              <template v-else-if="col.type === 'number'">
                <span @click="() => col.click?.(row)" class="cell-text">
                  {{ val(col, row).value }}
                </span>
              </template>

              <!-- 图像 -->
              <template v-else-if="col.type === 'image'">
                <t-image
                    :src="row[col.key] ?? '#'"
                    alt="image"
                    object-fit="contain"
                    preview
                    v-bind="col.attr"
                />
              </template>

              <!-- 其他 -->
              <template v-else>
                <span @click="() => col.click?.(row)" class="cell-text">
                  {{ val(col, row).value }}
                </span>
              </template>
            </div>
          </div>
        </TransitionGroup>

      </div>

      <!-- Loading遮罩层 -->
      <div v-if="$prop.loading" class="loading-mask">
        <div class="spinner"></div>
      </div>
    </div>
    <div class="table-footer">
      <slot name="footer"></slot>
    </div>
  </div>
</template>

<style scoped>
.table-container {
  position: relative;
  width: 100%;
  padding: 10px;
  user-select: none;
  background-color: #FFF;
  border-radius: 3px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}

.table-header {
  display: flex;
}

.table-footer {
  display: flex;
}

.table-body {
  border-left: 1px solid #f0f0f0;
  border-top: 1px solid #f0f0f0;
  border-radius: 5px;
  overflow-x: auto;
}

.header {
  position: sticky;
  top: 0;
  z-index: 10;
  height: 40px;
  background-color: #fbfbfb;
  transition: box-shadow 0.1s;
}

.header.is-scrolled {
  box-shadow: 0 4px 8px -2px rgba(47, 128, 237, 0.1);
}

.body {
  max-height: v-bind(height);
}

.row {
  transition: background-color 0.2s;
  height: 40px;
}

/* 树形行样式 */
.tree-row {
  background-color: #fafbfc;
}

.tree-level-1 {
  background-color: #f8f9fb;
}

.tree-level-2 {
  background-color: #f5f7fa;
}

.tree-level-3 {
  background-color: #f2f5f9;
}

.has-children {
  font-weight: 500;
}

.col {
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}

.col span {
  padding: 0 5px;
  display: inline-block;
  width: 100%;
}

.cell-text {
  color: inherit;
}

.tree-expand-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 3px;
  cursor: pointer;
  color: #6b7280;
  transition: all 0.2s;
}

.tree-expand-btn:hover {
  color: #2563eb;
}

.tree-expand-btn.expanded {
  color: #1c7bfb;
}

.expand-icon {
  transition: transform 0.2s;
  display: block;
  /* 确保 SVG 自身也居中 */
  margin: auto;
}

.tree-expand-btn.expanded .expand-icon {
  transform: rotate(90deg);
}

.tree-leaf-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 20px;
  height: 20px;
  color: #9ca3af;
}

/*插槽里面的元素*/
.slot-wrapper {
  display: flex;
  align-items: center;
}

.header > div,
.row > div {
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.header > div {
  color: #1f2d3d;
  border-bottom: 1px solid #f0f0f0;
  border-right: 1px solid #f0f0f0;
  display: flex;
  justify-content: center;
  align-items: center;
}

.row > div {
  font-weight: normal;
  font-size: 14px;
  color: #4f5b69;
  border-bottom: 1px solid #f0f0f0;
  border-right: 1px solid #f0f0f0;
  cursor: pointer;
}

.row:hover {
  background-color: #f0f7ff;
}

/* 树形表格专用样式 */
.tree-header-col {
  color: #1f2d3d;
  border-bottom: 1px solid #f0f0f0;
  border-right: 1px solid #f0f0f0;
  display: flex;
  justify-content: center;
  align-items: center;
  background-color: #fbfbfb;
}

/*Loading遮罩层*/
.loading-mask {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  /*backdrop-filter: blur(1px);*/
  /*background-color: rgba(255, 255, 255, 0.5);*/
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 99;
  pointer-events: all;
}

.spinner {
  width: 40px;
  height: 40px;
  border: 2px solid #2f80ed;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

/* 滚动条样式 */

/* 基础滚动条样式 */
.table-body {
  /* 确保显示滚动条 */
  overflow-x: auto;
  overflow-y: hidden;

  /* 滚动条整体样式 */
  scrollbar-width: thin; /* Firefox */
  scrollbar-color: #d1d5db #f9fafb; /* Firefox: 滑块颜色 轨道颜色 */
}

/* Webkit浏览器滚动条样式 (Chrome, Safari, Edge) */
.table-body::-webkit-scrollbar {
  height: 8px; /* 横向滚动条高度 */
  width: 8px; /* 纵向滚动条宽度(如果需要) */
}

/* 滚动条轨道 */
.table-body::-webkit-scrollbar-track {
  background: #f9fafb;
  border-radius: 4px;
  margin: 2px;
}

/* 滚动条滑块 */
.table-body::-webkit-scrollbar-thumb {
  background: linear-gradient(45deg, #d1d5db, #9ca3af);
  border-radius: 4px;
  border: 1px solid rgba(0, 0, 0, 0.1);
  transition: background 0.2s ease;
}

/* 滚动条滑块悬停效果 */
.table-body::-webkit-scrollbar-thumb:hover {
  background: linear-gradient(45deg, #9ca3af, #6b7280);
  cursor: pointer;
}

/* 滚动条滑块激活效果 */
.table-body::-webkit-scrollbar-thumb:active {
  background: linear-gradient(45deg, #6b7280, #4b5563);
}

/* 滚动条转角(如果同时有横向和纵向滚动条) */
.table-body::-webkit-scrollbar-corner {
  background: #f9fafb;
}

/* 固定列样式 */
.col[style*="position: sticky"][style*="left"],
.header > div[style*="position: sticky"][style*="left"],
.tree-header-col.sticky-left-zero {
  /* 分隔边框（右侧） */
  border-right: 1px solid #e5e7eb;
  /* 阴影（右侧内敛，不会太突兀） */
  box-shadow: 4px 0 8px -4px rgba(0, 0, 0, 0.12);
  background: #fff; /* 防透底，固定列建议保持不透明背景 */
}

/* 固定列：右侧 */
.col[style*="position: sticky"][style*="right"],
.header > div[style*="position: sticky"][style*="right"] {
  /* 分隔边框（左侧） */
  border-left: 1px solid #e5e7eb;
  /* 阴影（左侧） */
  box-shadow: -4px 0 8px -4px rgba(0, 0, 0, 0.12);
  background: #fff;
}

/* 提升表头固定列层级，避免被行内容覆盖（与你原来的 z-index=10 协同） */
.header > div[style*="position: sticky"] {
  z-index: 12;
}

/* 行内固定列的层级略高于普通单元格，低于表头 */
.row > .col[style*="position: sticky"] {
  z-index: 7;
}

/* 细腻一点的高亮效果（可选）：当鼠标悬停当前行时，固定列的阴影稍加强 */
.row:hover > .col[style*="position: sticky"][style*="left"] {
  box-shadow: 6px 0 10px -6px rgba(0, 0, 0, 0.18);
}

.row:hover > .col[style*="position: sticky"][style*="right"] {
  box-shadow: -6px 0 10px -6px rgba(0, 0, 0, 0.18);
}


/* 响应式滚动条 */
@media (max-width: 768px) {
  .table-body::-webkit-scrollbar {
    height: 6px; /* 移动端使用更细的滚动条 */
  }

  .table-body::-webkit-scrollbar-thumb {
    border-radius: 3px;
  }
}

/* 确保表格内容在滚动时的平滑过渡 */
.table-body {
  scroll-behavior: smooth;
}

/* 当内容宽度超出容器时显示滚动条提示 */
.table-body::before {
  content: '';
  position: absolute;
  right: 0;
  top: 0;
  bottom: 0;
  width: 20px;
  background: linear-gradient(to left, rgba(255, 255, 255, 0.8), transparent);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.3s ease;
  z-index: 5;
}

.table-body:hover::before {
  opacity: 1;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

/*动画效果*/
.tree-row-fade-enter-active,
.tree-row-fade-leave-active {
  transition: all 0.3s ease;
}

.tree-row-fade-enter-from,
.tree-row-fade-leave-to {
  opacity: 0;
  transform: translateY(-10px);
  height: 0;
  overflow: hidden;
}

.tree-row-fade-enter-to,
.tree-row-fade-leave-from {
  opacity: 1;
  transform: translateY(0);
  height: 40px;
}
</style>
